package com.xianggu.tomcat;

import com.xianggu.demo.service.AppConfig;
import com.xianggu.spring.XiangGuApplicationContent;
import com.xianggu.spring.annotation.RequestMapping;

import javax.servlet.Servlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author chengjy
 * @date 2025/3/6
 */
public class Tomcat {
    private Map<String, Context> contextMap = new HashMap<>();
    private Map<String, Object> contBeanMap = new HashMap<>();
    private XiangGuApplicationContent applicationContent;
    private boolean isDeployed = false;// true ？Servlet ： controller模式

    public Tomcat(XiangGuApplicationContent applicationContent) {
        // 内置容器
        this.applicationContent = applicationContent;
        contBeanMap = applicationContent.getContBeanMap();
    }

    public Tomcat() {
        this.deployApps();
        isDeployed = true;
    }

    public static void main(String[] args) {
        XiangGuApplicationContent applicationContent = new XiangGuApplicationContent(AppConfig.class);
        Tomcat tomcat = new Tomcat(applicationContent);
        tomcat.start(8080);
    }



    public void start(int port) {
        // Socket连接tcp

        try {
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            ServerSocket socket = new ServerSocket(port);
            System.out.println("tomcat启动成功");
            while (true) {
                Socket accept = socket.accept();
                executorService.execute( new SocketProcessor( accept , this));
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void start(int port , TomcatTaskable runnable) {
        // Socket连接tcp

        try {
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            ServerSocket socket = new ServerSocket(port);
            System.out.println("tomcat启动成功");
            while (true) {
                Socket accept = socket.accept();
                runnable.setTomcat(this , accept);
                executorService.execute( runnable);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void deployApps() {
        File webapps = new File(System.getProperty("user.dir") + "/webapps");
        if (webapps.exists()) {
            for (String appName : webapps.list()) {
                deployApp(webapps , appName);
            }
        }else{
            throw new RuntimeException("webapps文件夹不存在");
        }
    }

    private void deployApp(File webapps, String appName) {
        // servlet
        File appDirectory = new File(webapps, appName);
        File classesDirectory = new File(appDirectory, "classes");
        // 创建自定义类加载器
        WebAppsClassLoader webAppsClassLoader = null;
        try {
            webAppsClassLoader = new WebAppsClassLoader(new URL[]{classesDirectory.toURL()});
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }

        // 解析所有的class文件并注册
        Set<File> files = new HashSet<>();
        getAllFilePath(classesDirectory, files);
        System.out.println(files);

        Context context = new Context(appName);

        // 解析所有的class文件并注册
        for (File file : files) {
            String name = file.getPath();
            name = name.replace( classesDirectory + "\\" , "");
            name = name.replace(".class", "");
            name = name.replace("\\", ".");

            try {
                Class<?> aClass = webAppsClassLoader.loadClass(name);
                if(HttpServlet.class.isAssignableFrom(aClass)) {
                    if (aClass.isAnnotationPresent(WebServlet.class)) {
                        WebServlet annotation = aClass.getAnnotation(WebServlet.class);
                        String[] pathValue = annotation.value();
                        Object obj = aClass.getDeclaredConstructor().newInstance();
                        for (String path : pathValue) {
                            if(path.startsWith("/")){
                                path = path.substring(1,path.length());
                            }
                            context.addServlet(path, (Servlet) obj);
                        }
                    }
                }
                contextMap.put(appName, context);

            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 递归返回文件夹所有文件
     *
     * @param classesDirectory
     * @param files
     * @return
     */
    private void getAllFilePath(File classesDirectory, Set<File> files) {
        if (classesDirectory.isDirectory()) {
            for (File file : classesDirectory.listFiles()) {
                getAllFilePath(file, files);
            }
        }else{
            if(classesDirectory.getName().endsWith(".class") ){
                files.add(classesDirectory);
            }
        }
    }

    public Context getContextMap(String appName) {
        return contextMap.getOrDefault(appName , new Context(appName));
    }

    public Object getContBean(String path) {
        return contBeanMap.get(path);
    }

    public boolean isDeployed() {
        return isDeployed;
    }

    public XiangGuApplicationContent getApplicationContent() {
        return applicationContent;
    }
}
